package com.cy.common.aspect;

import com.cy.common.annotation.RequiredLog;
import com.cy.common.util.IPUtils;
import com.cy.common.util.ShiroUtils;
import com.cy.sys.pojo.sysLog;
import com.cy.sys.service.logService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Slf4j
@Component
//@Order(1)//通过提高写入日志的优先级来避免只读中包含写入的操作
public class SysLogAspect {
    @Pointcut("@annotation(com.cy.common.annotation.RequiredLog)")
    public void logPointCut(){}

    @Around("logPointCut()")

    public Object around(ProceedingJoinPoint jp) throws Throwable{
        try {
            Long a=System.currentTimeMillis();
            //方法执行于此
            Object result=jp.proceed();

            Long b=System.currentTimeMillis();
            saveUserLog(jp,b-a);
            //返回方法执行后的值
            return result;}
        catch (Throwable e){
            log.error(e.getMessage());
            throw e;
        }
    }
    @Autowired
    private logService logService;

    private void saveUserLog(ProceedingJoinPoint pj,Long time)throws Exception{
            String ip= IPUtils.getIpAddr();
          //  String username= ShiroUtils.getUsername();
        String username="hhh";
        Date createdTime=new Date();
        String operation=getOperation(pj);
        String method=getTargetClassMethod(pj);
        String params=new ObjectMapper().writeValueAsString(pj.getArgs());
        sysLog log=new sysLog();
        log.setIp(ip);
        log.setMethod(method);
        log.setCreatedTime(createdTime);
        log.setOperation(operation);
        log.setParams(params);
        log.setTime(time);
        log.setUsername(username);
        logService.saveObject(log);


    }
    //获取目标方法的全限定类名
    private String getTargetClassMethod(ProceedingJoinPoint pj)throws Exception{
        //获取目标对象类型
        Class<?> a=pj.getTarget().getClass();
        //对象的类全名
        String b=a.getName();
        MethodSignature ms= (MethodSignature) pj.getSignature();
        String c=ms.getName();
        return b+"."+c;
    }
    //获取目标方法上注解中的操作名
    private String getOperation(ProceedingJoinPoint pj) throws Exception{
        Class<?> a=pj.getTarget().getClass();
        MethodSignature ms=(MethodSignature) pj.getSignature();
        //不论jdk还是cglib代理都有效
        Method method=a.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
        //获取方法上的reqiredLog注解对象
        RequiredLog requiredLog=method.getAnnotation(RequiredLog.class);
        if(requiredLog==null)return "operation";
            return requiredLog.operation();
    }
}
